import uvicorn
import requests
import json
import asyncio

from fastapi.responses import StreamingResponse
from openai import OpenAI
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI(title="意图识别接口")


class FastGPTClient:
    def __init__(self, api_url: str, api_key: str):
        self.api_url = api_url
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }

    def get_reply(self, user_message: str) -> str:
        payload = {
            "stream": False,
            "detail": False,
            "messages": [{"role": "user", "content": user_message}]
        }
        response = requests.post(self.api_url, headers=self.headers, json=payload)

        if response.status_code != 200:
            raise HTTPException(status_code=response.status_code, detail="FastGPT 接口请求失败")

        data = response.json()
        return data["choices"][0]["message"]["content"]


class MatcherClient:
    def __init__(self, match_url: str):
        self.match_url = match_url
        self.headers = {
            "accept": "application/json",
            "Content-Type": "application/json"
        }

    def match_text(self, text: str):
        response = requests.post(self.match_url, headers=self.headers, json={"text": text})

        if response.status_code != 200:
            raise HTTPException(status_code=response.status_code, detail="匹配接口请求失败")

        return response.json()


class OutputResponse(BaseModel):
    api_reply: str
    user_input: str
    type: int


class UserInput(BaseModel):
    messages: list


def call_llm(prompt: str, system: str) -> dict:
    client = OpenAI(
        # 若没有配置环境变量，请用百炼API Key将下行替换为：api_key="sk-xxx",
        api_key="sk-064abae05a144789b9d1e5aebae9f567",
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    )
    messages = [
            {"role": "system", "content": system},
            {"role": "user", "content": prompt},
        ]
    print(messages)
    completion = client.chat.completions.create(
        # 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
        model="qwen3-32b",
        messages=messages,
        stream=True,  # 启用流式输出
        extra_body={"enable_thinking": False},
    )

    # 流式输出
    for chunk in completion:
        if chunk.choices[0].delta.content:
            print(chunk.choices[0].delta.content, end="", flush=True)
            yield chunk.choices[0].delta.content


def multi_call_llm(messages: list) -> dict:
    """
    多轮对话
    :param prompt:
    :param system:
    :return:
    """
    client = OpenAI(
        # 若没有配置环境变量，请用百炼API Key将下行替换为：api_key="sk-xxx",
        api_key="sk-064abae05a144789b9d1e5aebae9f567",
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    )

    completion = client.chat.completions.create(
        # 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
        model="qwen3-32b",
        messages=messages,
        stream=True,
        extra_body={"enable_thinking": False},
    )

    # 流式输出
    for chunk in completion:
        if chunk.choices[0].delta.content:
            print(chunk.choices[0].delta.content, end="", flush=True)
            yield chunk.choices[0].delta.content


# 实例化客户端
fastgpt_client = FastGPTClient(
    api_url="https://cloud.fastgpt.cn/api/v1/chat/completions",
    api_key="fastgpt-xj0KlYu8990DhwTXPE1obxtUnwNDkfjVhAILublmObjSSkoTx09wIt8b"
)
matcher_client = MatcherClient(match_url="http://192.168.1.101:8080/match/")


@app.post("/process/", summary="意图识别全流程接口(流式输出)")
def process_message(user_input: UserInput) -> StreamingResponse:
    async def generate_response():
        try:
            user_data = user_input.messages[-1]['content']

            # 单轮对话处理
            if len(user_input.messages) <= 2:
                gpt_reply = fastgpt_client.get_reply(user_data)
                print("fastgpt reply:", gpt_reply)

                # 普通大模型对话
                if "普通大模型对话" in gpt_reply:
                    reply = gpt_reply.split("+ ")[-1]
                    prompt_llm = reply
                    system_llm = "您是贵州省信息与计算科学重点实验室的心理咨询专家，请根据用户的问题来进行回答"

                    # 发送type信息
                    yield f"data: {json.dumps({'type': 1, 'user_input': reply})}\n\n"

                    # 流式输出LLM回复
                    for chunk in call_llm(prompt_llm, system_llm):
                        yield f"data: {json.dumps({'content': chunk})}\n\n"
                        await asyncio.sleep(0.01)  # 小延迟以避免过快输出

                # 心理问题处理
                elif "心理问题" in gpt_reply:
                    reply = gpt_reply.split("+ ")[-1]

                    # 第一步：提炼心理描述
                    prompt_1 = reply
                    system_1 = f"""你是一位资深心理咨询师和心理行为研究专家。

    【任务说明】
    用户将向你提供其当前的心理困扰或情绪体验。请根据输入内容：

    1. **提炼为一句话**，不超过50字；
    2. **使用心理学与行为科学的专业术语**进行描述；
    3. **准确反映心理动态与行为特征**；
    4. **句末附加该用户的典型心理行为特征**（如"伴有回避行为"）。

    【示例输入】
    我最近总觉得工作没有意义，做什么都提不起兴趣。

    【示例输出】
    出现职业倦怠与情绪低落，伴有兴趣减退和动力缺乏的行为特征。
    """
                    # 收集完整的回复用于匹配
                    llm_reply_1 = ""
                    for chunk in call_llm(prompt_1, system_1):
                        llm_reply_1 += chunk
                    match_result = matcher_client.match_text(llm_reply_1)
                    print("match result:", match_result)

                    # 发送type信息
                    yield f"data: {json.dumps({'type': 0, 'user_input': reply})}\n\n"

                    # 第二步：流式生成心理咨询回复
                    prompt_2 = f"""用户输入：{gpt_reply}\n匹配的json数据：\n{match_result}"""
                    system_2 = """您是贵州省信息与计算科学重点实验室的心理咨询专家，请遵循以下指导：

    1. 您是一名专业的心理咨询专家，介绍您的身份同时负责识别和分析用户可能存在的心理问题，并给予用户相应的心理安慰。
    2. 系统将提供一份与用户输入匹配的 JSON 数据，内容包括：
       - 匹配心理问题
       - 行为表现
       - 产生原因
       - 治疗或干预方法
    3. 请结合 JSON 数据与用户的输入，与其进行自然、温暖、有同理心的对话。
    4. 在对话过程中，请务必完成以下任务：
       - 明确告知用户其匹配到的心理问题；
       - 解释心理问题的产生原因，帮助用户理解自身状况；
       - 提供基于"解决方法"的针对性建议，帮助缓解心理困扰。
       - 请不要展现我们系统匹配的过程，在描述上面对用户透明。
    5. 目标是帮助用户正确认识自身心理状态，并提供专业、个性化的心理支持。
    6. 面向的是青年学生，在称呼用户时可以称呼为同学。
    7. 以Markdown格式来生成结果，并且生成一些有用、好看的文字图标。"""

                    for chunk in call_llm(prompt_2, system_2):
                        yield f"data: {json.dumps({'content': chunk})}\n\n"
                        await asyncio.sleep(0.01)

                # 知识点处理
                elif "知识点" in gpt_reply:
                    reply = gpt_reply.split("+ ")[-1]
                    yield f"data: {json.dumps({'type': 2, 'user_input': reply, 'content': '知识点功能暂未实现'})}\n\n"

            # 多轮对话处理
            else:
                system = """你是贵州省信息与计算科学重点实验室的一位专业心理专家，精通心理咨询与心理行为分析。

    【任务目标】
    请根据用户与助手之间的多轮对话内容，全面分析用户的心理状态与潜在困扰，并使用心理学专业知识对用户的表达进行深入理解和回应。

    【输入内容】
    将传入一段完整的用户与助手的多轮对话内容。

    【输出要求】
    1. 结构清晰：
       - 可按段落或逻辑模块整理内容；
       - 先对用户进行安慰，针对具体问题分析部分可分为"心理观察"、"情绪分析"、"行为特征"、"专业回应"等模块。

    2. 专业性强：
       - 使用心理学术语和理论模型（如认知行为、情绪调节、自我认知、回避行为等）；
       - 同时要进行安慰用户的心理状态。

    3. 基于对话内容逐步分析：
       - 提炼用户表达中的核心信息；
       - 分析其情绪变化、语言特征与潜在心理需求；
       - 如有明显心理困扰，给出合理建议。

    4. 回应风格：
       - 专业、共情、温和；
       - 不要通过匹配结果直接下诊断，只能说是可能，同时提供建设性建议和可执行的心理调节策略。"""

                flag = 0
                if len(user_input.messages) > 5:
                    user_messages = user_input.messages[-5:]
                else:
                    user_messages = user_input.messages

                for message in user_messages:
                    role = message["role"]
                    if role == "system":
                        message["content"] = system
                        flag = 1
                if flag == 0:
                    user_messages.insert(0, {"role": "system", "content": system})

                # 发送type信息
                yield f"data: {json.dumps({'type': 3, 'user_input': user_data})}\n\n"

                # 流式输出多轮对话回复
                for chunk in multi_call_llm(user_messages):
                    yield f"data: {json.dumps({'content': chunk})}\n\n"
                    await asyncio.sleep(0.01)

            # 发送结束标记
            yield f"data: {json.dumps({'done': True})}\n\n"

        except HTTPException as e:
            yield f"data: {json.dumps({'error': str(e.detail)})}\n\n"
        except Exception as e:
            yield f"data: {json.dumps({'error': str(e)})}\n\n"

    return StreamingResponse(
        generate_response(),
        media_type="text/plain",
        headers={
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "Content-Type": "text/event-stream"
        }
    )


# uvicorn.run(app, host="192.168.1.101", port=8088)
uvicorn.run(app, host="127.0.0.1", port=8088)
# uvicorn.run(app, host="172.20.0.89", port=8088)

# user_input = "我最近有点烦躁，不想学习"